﻿/*
 * @author Lee 
 * Time: 20180403 
 * Abstract: SharePoint API的二次封装
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;

namespace SharePointHelper.DLL.SSOM
{
	public class Log
	{
		public enum LogLevel
		{
			Error,
			Warning,
			Information,
		}


        #region 写入一个log实体
        /// <summary>
        /// 写入一个log实体
        /// </summary>
        /// <param name="uniqueCode"></param>
        /// <param name="title"></param>
        /// <param name="bodyPlainText">这应该是纯文本，member将处理编码的ULS</param>
        /// <param name="severityLevel"></param>
        /// <param name="isWriteSharePointUls"></param>
        /// <param name="emailTo">emails 数组. If null,会给每个人发email</param>
        /// <returns></returns>
        public static string Write(string uniqueCode, string title, string body, 
			LogLevel severityLevel, bool isWriteTextLog, bool isWriteSharePointUls, string stackTrace, 
			string[] emailTo, string emailFrom)
		{
			string htmlOutput = string.Empty;
			string ulsCategory = Constants.UlsCategory;
			try
			{
				if (title != "Thread was being aborted.")
				{
					// title
					if (!string.IsNullOrEmpty(uniqueCode))
					{ title = "[" + severityLevel.ToString() + ": " + uniqueCode + "] " + title; }
					
					// 输出html
					string htmlTitle = title;
					try { htmlTitle = System.Web.HttpUtility.HtmlEncode(Utilities.RemoveHtmlTags(htmlTitle)); } 
					catch { }
					htmlOutput = "<div class='error1'>" + htmlTitle + "</div>";
					if (!string.IsNullOrEmpty(body))
					{ 
						htmlOutput += "<div class='error2'>"
							+ System.Web.HttpUtility.HtmlEncode(body) + "</div>";
					}


					// error stack
					if (string.IsNullOrEmpty(stackTrace)) { stackTrace = GetStack(); }
					body += "\r\n\r\nSTACK TRACE:\r\n" + stackTrace;
					htmlOutput += "<br/><hr/>STACK TRACE:<br/>" + System.Web.HttpUtility.HtmlEncode(stackTrace) + "<br/><br/>";

					// footer
					body += Footer(false);
					htmlOutput += Footer(true);


					///////////////////////////////////////////////////////////////////////////
					///////////////////////////////////////////////////////////////////////////
					// 1.) 写入 text log
					if (isWriteTextLog) { WriteTextLog(title, body); }


					///////////////////////////////////////////////////////////////////////////
					///////////////////////////////////////////////////////////////////////////
					// 2.) 写入 ULS
					if (isWriteSharePointUls)
					{
						WriteUls(title, body, severityLevel, ulsCategory, stackTrace);
					}

					///////////////////////////////////////////////////////////////////////////
					///////////////////////////////////////////////////////////////////////////
					// 3.) email
					if (emailTo != null && emailTo.Length > 0)
					{
						if (string.IsNullOrEmpty(emailFrom)) { emailFrom = Constants.EmailDefaultSender; }
						if (!Utilities.Email(emailFrom, emailTo, null, null, title, true, title + "\n\n" + body, 
							false, false, false))
						{
							throw new Exception("Failed to send email with subject: " + title);
						}
					}

				}
			}
			catch (Exception ex)
			{
				WriteTextLog(ex.Message, ex.ToString() + "\n\n\nOriginal Error: " + title + "\n\n" + body);
			}
			return htmlOutput;
		}
        #endregion

        #region 写入一个 text log
        /// <summary>
        /// 写入一个 text log
        /// </summary>
        /// <param name="title"></param>
        /// <param name="body"></param>
        public static void WriteTextLog(string title, string body)
		{
			System.IO.FileMode mode;
			if (System.IO.File.Exists(Constants.LogPath)) { mode = System.IO.FileMode.Append; }
			else { mode = System.IO.FileMode.CreateNew; }

			using (System.IO.FileStream fs = new System.IO.FileStream(Constants.LogPath, mode))
			{
				using (System.IO.StreamWriter logger = new System.IO.StreamWriter(fs))
				{
					string lineSeparator = "\n__________________________________________________________________________________________________";
					logger.WriteLine(lineSeparator + "\n" + lineSeparator + "\n");
					logger.WriteLine("Date/Time: " + DateTime.Now.ToString() + "\n");
					logger.WriteLine(title + "\n");
					logger.WriteLine(body);
					logger.WriteLine("\n" + lineSeparator + "\n" + lineSeparator);
					logger.Close();
					logger.Dispose();
				}
				fs.Close();
				fs.Dispose();
			}
		}
        #endregion

        #region 写入 SharePoint ULS logger
        /// <summary>
        /// 写入 SharePoint ULS logger
        /// </summary>
        /// <param name="title"></param>
        /// <param name="body"></param>
        /// <param name="severityLevel"></param>
        /// <param name="ulsCategory"></param>
        public static void WriteUls(string title, string body, LogLevel severityLevel, string ulsCategory,
			string stackTrace)
		{
			try
			{
				// 初始化
				EventSeverity sharePointSeverity = EventSeverity.ErrorCritical;
				TraceSeverity severity = TraceSeverity.High;
				if (string.IsNullOrEmpty(ulsCategory)) { ulsCategory = Constants.UlsCategory; }

				if (severityLevel == LogLevel.Warning)
				{
					sharePointSeverity = EventSeverity.Warning;
					severity = TraceSeverity.Medium;
				}
				else if (severityLevel == LogLevel.Information)
				{
					sharePointSeverity = EventSeverity.Information;
					severity = TraceSeverity.Verbose;
				}
			
				SPDiagnosticsService.Local.WriteTrace(0,
					new SPDiagnosticsCategory(ulsCategory, severity, sharePointSeverity), severity,
					title + "\n\n" + body, stackTrace);
			}
			catch (Exception ex)
			{
				WriteTextLog("Failed to write SharePoint ULS Log", ex.ToString());
			}
		}
        #endregion

        #region 在电子邮件的页脚包含诊断信息
        /// <summary>
        /// 在电子邮件的页脚包含诊断信息
        /// </summary>
        /// <param name="isHtmlFormat"></param>
        /// <param name="isLogOnError"></param>
        /// <returns></returns>
        public static string Footer(bool isHtmlFormat)
		{
			string o = null;
			try
			{
				// 初始化
				string unknown = "Unknown";
				string separator = "\n"; if (isHtmlFormat) { separator = "<br/>"; }
				o += separator + separator;


				////////////////////////////////
				// 用户名
				string username = unknown;
				if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.User != null
					&& System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
				{
					username = System.Web.HttpContext.Current.User.Identity.Name;
					if (!string.IsNullOrEmpty(username)) { username = Security.FormatUsername(username); }
				}
				o += "Username: " + username + separator;

				////////////////////////////////
				// ip address
				string ipAddress = unknown;
				if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Request != null
					&& System.Web.HttpContext.Current.Request.UserHostAddress != null)
				{
					ipAddress = System.Web.HttpContext.Current.Request.UserHostAddress;
				}
				o += "User IP Address: " + ipAddress + separator;

				////////////////////////////////
				// server
				string serverComputername = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
				if (string.IsNullOrEmpty(serverComputername)) { serverComputername = unknown; }
				o += "Sever Name: " + serverComputername + separator;

				////////////////////////////////
				// URL
				string url = unknown;
				if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Request != null
					&& System.Web.HttpContext.Current.Request.Url != null)
				{
					url = System.Web.HttpContext.Current.Request.Url.ToString();
				}
				o += "URL: " + url + separator;

				////////////////////////////////
				// referrer url
				string urlReferrer = null;
				if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Request != null
					&& System.Web.HttpContext.Current.Request.UrlReferrer != null)
				{
					urlReferrer = System.Web.HttpContext.Current.Request.UrlReferrer.ToString();
				}
				o += "Referrer: " + urlReferrer + separator;

				// 格式化 footer
				if (isHtmlFormat)
				{
					o = "<div style='color:gray; font-size:10px; font-family:arial; margin-top:10px;'>" + o + "</div>";
				}
			}
			catch (Exception ex)
			{
				WriteTextLog("Error in Footer: " + ex.Message, ex.ToString());
				o = null;
			}
			return o;
		}
        #endregion

        #region 获取错误堆栈信息
        /// <summary>
        /// 获取错误堆栈信息
        /// </summary>
        /// <returns></returns>
        public static string GetStack()
		{
			string o = null;

			var s = new System.Diagnostics.StackTrace();
			var frames = s.GetFrames();

			foreach (System.Diagnostics.StackFrame f in frames)
			{
				int lineNumber = f.GetFileLineNumber();
				if (lineNumber > 0)
				{
					o += string.Format("Line: {0}\tFile: {1}\tMethod: {2}\r\n", lineNumber, f.GetFileName(), f.GetMethod());
				}
				else
				{
					// 退出循环, 不再获取堆栈信息
					break;
				}
			}
			return o;
		}
        #endregion

        #region 判断当前 server 是否是开发环境
        /// <summary>
        /// 判断当前 server 是否是开发环境
        /// 基于 web.config appSettings
        /// </summary>
        /// <returns></returns>
        public static bool IsDevelopmentEnvironment()
		{
			bool isDevelopmentEnvironment = false;
			try
			{
				System.Configuration.Configuration webConfig =
					System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
				if (webConfig.AppSettings.Settings.Count > 0)
				{
					System.Configuration.KeyValueConfigurationElement isDev = webConfig.AppSettings.Settings["IsDev"];
					if (isDev != null && !string.IsNullOrEmpty(isDev.Value))
					{
						try
						{
							// try to parse value
							isDevelopmentEnvironment = !Convert.ToBoolean(isDev.Value);
						}
						catch { }
					}
				}
			}
			catch { isDevelopmentEnvironment = false; }
			return isDevelopmentEnvironment;
		}
        #endregion

        #region 写入一个 error log entry, 会自动写入到本地 log 文件, SharePoint log, 以及发送 email
        /// <summary>
        /// 写入一个 error log entry, 会自动写入到本地 log 文件, SharePoint log, 以及发送 email
        /// </summary>
        /// <param name="uniqueCode">og entry的唯一身份标识字符串</param>
        /// <param name="ex">Exception object passed from try/catch block</param>
        /// <returns></returns>
        public static string WriteError(string uniqueCode, Exception ex)
		{
			try  { return WriteError(uniqueCode, ex, null); }
			catch { return string.Empty; }
		}

        /// <summary>
        /// 写入一个 error log entry, 会自动写入到本地 log 文件, SharePoint log, 以及发送 email
        /// </summary>
        /// <param name="uniqueCode">og entry的唯一身份标识字符串</param>
        /// <param name="ex">Exception object passed from try/catch block</param>
        /// <param name="extraErrorInformation">要传递的任何其他信息，如参数值</param>
        /// <returns></returns>
        public static string WriteError(string uniqueCode, Exception ex, string extraErrorInformation)
		{
			try
			{
				string title = string.Empty;
				string body = string.Empty;
				string stackTrace = string.Empty;
				if (ex != null) { title = ex.Message; body = ex.ToString(); stackTrace = ex.StackTrace; }
				if (!string.IsNullOrEmpty(extraErrorInformation)) { body = extraErrorInformation + "\n\n" + body; }

				return Write(uniqueCode, title, body, LogLevel.Error, false, true, 
					stackTrace, Constants.EmailDefaultErrorLogRecipients, null);
			}
			catch { return string.Empty; }
		}

        /// <summary>
        /// 写入一个 error log entry, 会自动写入到本地 log 文件, SharePoint log, 以及发送 email
        /// </summary>
        /// <param name="uniqueCode">log entry的唯一身份标识字符串</param>
        /// <param name="title"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        public static string WriteError(string uniqueCode, string title, string body)
		{
			try
			{
				return Write(uniqueCode, title, body, LogLevel.Error, false, true, null, 
					Constants.EmailDefaultErrorLogRecipients, null);
			}
			catch { return string.Empty; }
		}

        /// <summary>
        /// 写入一个 error log entry, 会自动写入到本地 log 文件, SharePoint log, 以及发送 email
        /// </summary>
        /// <param name="uniqueCode">log entry的唯一身份标识字符串</param>
        /// <param name="title"></param>
        /// <returns></returns>
        public static string WriteError(string uniqueCode, string title)
		{
			try { return Write(uniqueCode, title, null, LogLevel.Error, false, true, null, 
				Constants.EmailDefaultErrorLogRecipients, null); }
			catch { return string.Empty; }
		}
        #endregion

        public static string WriteInformation(string title)
		{
			try { return Write(string.Empty, title, string.Empty, LogLevel.Information, false, true, null, null, null); }
			catch { return string.Empty; }
		}

		public static string WriteInformation(string uniqueCode, string title)
		{
			try { return Write(uniqueCode, title, string.Empty, LogLevel.Information, false, true, null, null, null); }
			catch { return string.Empty; }
		}

		public static string WriteInformation(string uniqueCode, string title, bool isEmail)
		{
			string[] emailsToSendTo = null; if (isEmail) { emailsToSendTo = Constants.EmailDefaultErrorLogRecipients; }
			try { return Write(uniqueCode, title, string.Empty, LogLevel.Information, false, true, null, emailsToSendTo, null); }
			catch { return string.Empty; }
		}
	}
}
